// TelnetLayer.cpp: implementation of the CTelnetLayer class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "AnsiTerminal.h"
#include "TelnetLayer.h"

#include "TelnetLogger.h"
#include "GlobalConsts.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

char OptionBuf[3] = { IAC };
char CharBuf[5];

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////


CTelnetLayer::CTelnetLayer() :
m_optionCol(this),
m_cmdip(this, &m_optionCol)
{
	m_socketLayer.RegisterEvent(this);
	m_pCharStreamFilter = NULL;
	m_pTelnetLogger = NULL;

// 	m_socketDataSinkWnd.Create(NULL, "SocketDataSinkWnd", 0, CRect(0, 0, 0, 0), CWnd::FromHandle(HWND_MESSAGE), 0);
// 	ASSERT(m_socketDataSinkWnd.GetSafeHwnd());
	
	m_pKeyMap = NULL;
}

CTelnetLayer::~CTelnetLayer()
{
	
}

void CTelnetLayer::OnSocketClosed()
{
	if(m_pEvents)
	{
		m_pEvents->OnDisconnect();
	}
}

// UINT CTelnetLayer::ReadThreadProc(LPVOID pObj)
// {
// 	CTelnetLayer* pThis = (CTelnetLayer*)pObj;
// 	pThis->ReadThread();
// 	return 0;
//}
// 
// void CTelnetLayer::ReadThread()
// {
// 	char c = '\0';
// 	try
// 	{
// 		for(;;)
// 		{
// 			c = m_socketLayer.ReadChar();
// 			m_socketDataSinkWnd.SendMessage(WM_SOCKET_CHAR, c);
// 		}
// 	}
//  	catch(...)
//  	{
// 		afxDump << "ReadThread Exception!" << "\n";
//  	}
// }
 
void CTelnetLayer::Connect(const CString& host, int port/* = 23 */)
{
	ASSERT(!m_socketLayer.IsConnected());
	m_socketLayer.Connect(host, port);
	//beginReadThread();

//	AfxBeginThread(ReadThreadProc, this);
}

BOOL CTelnetLayer::IsConnected()
{
	return m_socketLayer.IsConnected();
}

void CTelnetLayer::Disconnect()
{
	ASSERT(m_socketLayer.IsConnected());
	m_socketLayer.Disconnect();
}

void CTelnetLayer::RegisterEvents(CTelnetLayerEvents *pEvents)
{
	m_pEvents = pEvents;
}

void CTelnetLayer::OnSocketChar(char c)
{
	if(m_pTelnetLogger)
	{
		m_pTelnetLogger->ReceiveChar(c);
	}

	//afxDump << "### " << (BYTE)c << "\n";
	if(m_cmdip.EatChar(c))
	{
		; // do nothing
	}
	else
	{
		if(m_pCharStreamFilter)
			m_pCharStreamFilter->EatChar(c);

		if(m_pTelnetLogger)
		{
			m_pTelnetLogger->AddLogPoint(DIR_RECEIVE, LOG_CHAR, 1);
			//m_pTelnetLogger->AddLogPoint(DIR_RECEIVE, LOG_CHAR);
		}
	}	
}

void CTelnetLayer::SetCharStreamFilter(ICharStreamFilter *pCharStreamFilter)
{
	m_pCharStreamFilter = pCharStreamFilter;
}

//

void CTelnetLayer::SendOptionCommand(char optionType, char action)
{
	OptionBuf[1] = action;
	OptionBuf[2] = optionType;

	m_socketLayer.SendBuf(OptionBuf, 3);

	if(m_pTelnetLogger)
	{
		m_pTelnetLogger->SendChars(OptionBuf, 3);
		m_pTelnetLogger->AddLogPoint(DIR_SEND, LOG_COMMAND, 3);
		//m_pTelnetLogger->AddLogPoint(DIR_SEND, LOG_COMMAND);
	}

}

void CTelnetLayer::SendOptionParameters(char optionType, const CArray<char, char> &parameters)
{
	int paramSize = parameters.GetSize();
	int len = paramSize + 5;
	char *buf = new char[len];
	buf[0] = IAC;
	buf[1] = SB;
	buf[2] = optionType;
	//strncpy(buf + 3, parameters.GetData(), paramSize);
	for(int n = 0; n < paramSize; n++)
	{
		buf[3 + n] = parameters[n];
	}
	buf[len - 2] = IAC;
	buf[len - 1] = SE;

	m_socketLayer.SendBuf(buf, len);

	if(m_pTelnetLogger)
	{
		m_pTelnetLogger->SendChars(buf, len);
		m_pTelnetLogger->AddLogPoint(DIR_SEND, LOG_OPTION, len);
		//m_pTelnetLogger->AddLogPoint(DIR_SEND, LOG_OPTION);
	}

	delete[] buf;
}

void CTelnetLayer::SetTelnetLogger(CTelnetLogger *pTelnetLogger)
{
	m_pTelnetLogger = pTelnetLogger;
	m_cmdip.SetTelnetLogger(pTelnetLogger);
}

void CTelnetLayer::SetKeyMap(ITerminalKeyMap *pKeyMap)
{
	m_pKeyMap = pKeyMap;
}

void CTelnetLayer::OnKeyPress(char c)
{
	if(!IsConnected())
	{
		return;
	}
	m_socketLayer.SendChar(c);
}

void CTelnetLayer::OnKeyDown(WORD key, BYTE fVirt)
{
	if(!IsConnected())
	{
		return;
	}
	if(!m_pKeyMap)
	{
		return;
	}
	CString s = m_pKeyMap->TranslateKey(key, fVirt);
	if(s.IsEmpty())
	{
		return;
	}
	m_socketLayer.SendText(s);
}